"""
文件名称: dinkelbach_user_association.py
功能: 使用dinkelbach算法求解用户关联策略(外层)
作者: 喻越
创建日期: 2025-01-15
"""
# from ..parameter.constant import const
# import cvxpy as cp
# import numpy as np
# from ..model.models import *
from .ccp_user_association import ccp_user
from .performance_calculations import compute_p_available, compute_B, compute_E, compute_CE
from .system_initialization import *


def random_restart(res_x_bs_ue, bs_status, possible_random):
    bs_num = res_x_bs_ue.shape[1]
    ue_num = res_x_bs_ue.shape[0]
    bs_all_index = np.array([k for k in range(bs_num)])  # shape=[bs_num,-] TODO
    bs_sleep_index = np.where(bs_status == 0)[1]  # shape=[N_bs_sleep,-]
    bs_work_index = np.isin(bs_all_index, bs_sleep_index, invert=True)  # 求补集 Bool值
    bs_work_index = bs_all_index[bs_work_index]  # 工作基站索引
    for j in range(int(ue_num)):
        if np.random.rand() <= possible_random:
            i = np.random.choice(bs_work_index)
            res_x_bs_ue[j, :] = int(0)
            res_x_bs_ue[j, i] = int(1)

    return res_x_bs_ue


#  用户关联
def user_association(res_x_bs_ue, bs_status, p_pv, rb_req, l_bs_ue, h_bs_ue):
    '''
    用户关联：外层Dinkelbach算法
    :param res_x_bs_ue: 基站用户关联变量（求解量）
    :param bs_status: 基站休眠变量
    :param p_pv: 基站光伏能量
    :param rb_req: 用户需求资源块数
    :param l_bs_ue: 基站用户距离
    :param h_bs_ue: 基站用户信道状态
    :return: res_x_bs_ue: 基站用户关联变量
    '''
    bs_num = l_bs_ue.shape[1]
    ue_num = l_bs_ue.shape[0]
    # Dinkelbach算法
    x_list = []
    ce_temp = 1000
    ce_list = [ce_temp]
    converged = False
    I = 100
    i = 1
    possible_random = 0.8
    p_available = p_pv  # 基站可用能量
    res_x_bs_ue_list = [res_x_bs_ue]
    while not converged and i <= I:
        print(i)
        if (i % 10 == 0):  # 如果i能整除10,说明10算法还没收敛,引入随机取解
            res_x_bs_ue = random_restart(res_x_bs_ue, bs_status, possible_random)
            # res_x_bs_ue =
        #  使用CCP算法解决凸凹优化问题（内层）
        res_x_bs_ue = ccp_user(res_x_bs_ue, ce_temp, bs_status, p_available, rb_req, l_bs_ue, h_bs_ue)
        res_x_bs_ue_list.append(res_x_bs_ue)
        error = abs(
            compute_B(res_x_bs_ue, h_bs_ue, l_bs_ue, rb_req) - ce_temp * compute_E(res_x_bs_ue, p_pv, bs_status,
                                                                                   rb_req))
        if error <= 1e-03:
            converged = True
            break
        else:
            ce_temp = compute_CE(res_x_bs_ue, p_pv, bs_status, h_bs_ue, l_bs_ue, rb_req)

            ce_list.append(ce_temp)
            i = i + 1

    if converged == True:
        print('用户关联dinkelbach算法第' + str(i) + '轮收敛!')
        # res_x_bs_ue_n = nearby_access(bs_pos, ue_pos, bs_status, rb_req)
        print("\n就近接入的CE的最大值",
              f'{compute_CE(res_x_bs_ue_list[0], p_pv, bs_status, h_bs_ue, l_bs_ue, rb_req):.2e}')
        print("\n用户共享优化后CE的最大值",
              f'{compute_CE(res_x_bs_ue, p_pv, bs_status, h_bs_ue, l_bs_ue, rb_req):.2e}')

    else:
        print('用户关联dinkelbach算法没有收敛！！')
    return res_x_bs_ue

# np.random.seed(const.SEED)
# bs_num = const.BS_NUM
# ue_num = const.UE_NUM_SEQUENCE[0]
# bs_pos = uniform2d(bs_num - 1, const.L)
# bs_pos = macro_bs_init(bs_pos, const.L)
# ue_pos = uniform2d(ue_num, const.L)
#
# # 初始化光伏能量
# p_pv = np.random.poisson(const.PV_A, [1, const.BS_NUM])  # shape=[24, bs_num]
# s_pv = [const.S_PV_MICRO for i in range(const.BS_NUM - 1)]
# s_pv.insert(0, const.S_PV_MACRO)
# p_pv = p_pv * s_pv * const.GAMMA_PV
# # 初始化用户要求和信道状态
# ue_snr_theta = np.random.randint(const.SINR_MIN, const.SINR_MAX, size=[ue_num, 1])
# h_bs_ue = channel_status(bs_num, ue_num)
#
# bs_status = np.array([[1, 0, 0, 0]])
# ce_temp = 1000
# l_bs_ue = distance_calculation(bs_pos, ue_pos)  # 测算距离
# _, rb_req = rb_demand(ue_snr_theta, l_bs_ue, h_bs_ue)
# # 初始为就近接入
# res_x_bs_ue = nearby_access(bs_pos, ue_pos, bs_status, rb_req)
#
# result = user_association(res_x_bs_ue, bs_status, p_pv, rb_req, l_bs_ue, h_bs_ue)
